using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Messaging;
using System.Configuration;
using System.Runtime.InteropServices;
using SMSservice;
using System.Data;
namespace SMSservice
{
    class WindowsService : ServiceBase
    {
        /// <summary>
        /// Public Constructor for WindowsService.
        /// </summary>
        #region variable decl
        SerialPort port = null;
        Database.DataBase database = null;
        DataTable dataSend = null;
        gmsClass gms = null;
        private MessageQueue inQueue = null;
        private MessageQueue outQueue = null;
        Thread readThread = null;
        Thread sendThread = null;
        string phoneNum = "";
        string smgText = "";
        bool isReading = true;
        bool isSending = true;
        #endregion
        public WindowsService()
        {

            initService();

            initMsgQueue();

            gms = new gmsClass();
            
        }
        /*
         * setting for message queue
         */
        public void initMsgQueue()
        {
            // create queue for read message
            if (MessageQueue.Exists(serviceConstant.IN_MESSAGE_QUEUE))
                inQueue = new MessageQueue(serviceConstant.IN_MESSAGE_QUEUE);
            else
                inQueue = MessageQueue.Create(serviceConstant.IN_MESSAGE_QUEUE);
            // create queue for send message
            if (MessageQueue.Exists(serviceConstant.OUT_MESSAGE_QUEUE))
                outQueue = new MessageQueue(serviceConstant.OUT_MESSAGE_QUEUE);
            else
                outQueue = MessageQueue.Create(serviceConstant.OUT_MESSAGE_QUEUE);
        }

        /**
         *setting for service 
         */
        public void initService()
        {
            this.ServiceName = "My Windows Service";
            this.EventLog.Source = "My Windows Service";
            this.EventLog.Log = "Application";


            // These Flags set whether or not to handle that specific
            //  type of event. Set to true if you need it, false otherwise.
            this.CanHandlePowerEvent = true;
            this.CanHandleSessionChangeEvent = true;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
            this.CanStop = true;
        }

        /// <summary>
        /// The Main Thread: This is where your Service is Run.
        /// </summary>
        static void Main()
        {
            ServiceBase.Run(new WindowsService());
        }

        /// <summary>
        /// Dispose of objects that need it here.
        /// </summary>
        /// <param name="disposing">Whether or not disposing is going on.</param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        /// <summary>
        /// OnStart: Put startup code here
        ///  - Start threads, get inital data, etc.
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
            create();
            start();
        }

        /// <summary>
        /// OnStop: Put your stop code here
        /// - Stop threads, set final data, etc.
        /// </summary>
        protected override void OnStop()
        {
            base.OnStop();
            isReading = false;
            isSending = false;
            
        }
       
        /// <summary>
        /// OnPause: Put your pause code here
        /// - Pause working threads, etc.
        /// </summary>
        protected override void OnPause()
        {
            base.OnPause();
        }

        /// <summary>
        /// OnContinue: Put your continue code here
        /// - Un-pause working threads, etc.
        /// </summary>
        protected override void OnContinue()
        {
            base.OnContinue();
           
        }

        /// <summary>
        /// OnShutdown(): Called when the System is shutting down
        /// - Put code here when you need special handling
        ///   of code that deals with a system shutdown, such
        ///   as saving special data before shutdown.
        /// </summary>
        protected override void OnShutdown()
        {
            base.OnShutdown();
        }

        /// <summary>
        /// OnCustomCommand(): If you need to send a command to your
        ///   service without the need for Remoting or Sockets, use
        ///   this method to do custom methods.
        /// </summary>
        /// <param name="command">Arbitrary Integer between 128 & 256</param>
        protected override void OnCustomCommand(int command)
        {
            //  A custom command can be sent to a service by using this method:
            //#  int command = 128; //Some Arbitrary number between 128 & 256
            //#  ServiceController sc = new ServiceController("NameOfService");
            //#  sc.ExecuteCommand(command);

            base.OnCustomCommand(command);
        }

        /// <summary>
        /// OnPowerEvent(): Useful for detecting power status changes,
        ///   such as going into Suspend mode or Low Battery for laptops.
        /// </summary>
        /// <param name="powerStatus">The Power Broadcase Status (BatteryLow, Suspend, etc.)</param>
        protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
        {
            return base.OnPowerEvent(powerStatus);
        }

        /// <summary>
        /// OnSessionChange(): To handle a change event from a Terminal Server session.
        ///   Useful if you need to determine when a user logs in remotely or logs off,
        ///   or when someone logs into the console.
        /// </summary>
        /// <param name="changeDescription"></param>
        protected override void OnSessionChange(SessionChangeDescription changeDescription)
        {
            base.OnSessionChange(changeDescription);
        }
        /**
        * setting for port
        */
        public void Setting(int baudRate, Parity parity, int databit, StopBits stopBit)
        {

            port.BaudRate = baudRate;
            port.Parity = parity;
            port.DataBits = databit;
            port.StopBits = stopBit;
        }
        public void create()
        {
            try
            {
                string portName = ConfigurationManager.AppSettings["Port"];
                string baudRate = ConfigurationManager.AppSettings["BaudRate"];
                string dataBit =  ConfigurationManager.AppSettings["DataBit"];
                string readTime = ConfigurationManager.AppSettings["ReadTimeOut"];
                string writeTime = ConfigurationManager.AppSettings["WriteTimeOut"];

                port = gms.OpenPort(portName, Int32.Parse(baudRate), Int32.Parse(dataBit), Int32.Parse(readTime), Int32.Parse(writeTime));
                database = new Database.DataBase();
            }
            catch (Exception e)
            {
                EventLog.WriteEntry("SMSmessage", e.Message, EventLogEntryType.Error);
            }

        }
        public void start()
        {
            //readThread = new Thread(new System.Threading.ThreadStart(readSMS));
            sendThread = new Thread(new System.Threading.ThreadStart(autoSend));
           // readThread.IsBackground = true;
            sendThread.IsBackground = true;
            //readThread.Start();
            sendThread.Start();
        }
        // read sms in Queue
        public void readSMS()
        {
            do
            {
                Thread.Sleep(5000);
                List<ShortMessage> messages = gms.ReadSMS(port, serviceConstant.READ_UNREAD);
                foreach (ShortMessage message in messages)
                {
                    inQueue.Send(message);
                }
            } while (isReading);
        }

        /*
         * send sms using queue
         */
        public void sendSMS()
        {

            do
            {
                Message mss = null ;
                try
                {
                    mss = outQueue.Receive();
                    if (mss != null)
                    {
                        smsClass smsPkg = mss.Body as smsClass;

                        if( smsPkg != null){

                            phoneNum = smsPkg.PhoneNumber;

                            smgText = smsPkg.SMSText;

                            gms.sendMsg(port, phoneNum, smgText);
                        }
                    }
                }
                catch (Exception e)
                {
                    EventLog.WriteEntry("Error", e.Message, EventLogEntryType.Error);
                }

            } while (isSending);
        }
        // send sms using DB
        public bool sendMessage(string phoneNumber, string text)
        {
            // send message with phone and message
            if (gms.sendMsg(port, phoneNumber, text))
            {
                //"Message is sent successfully"
                return true;
            }
            else
            {
                //"Fail to sent message"
                return false;
            }
        }
        private void autoSend()
        {
            bool result = false;
            double date;
            string phone;
            string text;
            string id;
            while (true)
            {
                Thread.Sleep(1000);
                dataSend = database.getSMS();
                for (int i = 0; i < dataSend.Rows.Count; i++)
                {
                    id = dataSend.Rows[i]["id"].ToString();
                    phone = dataSend.Rows[i]["sdt"].ToString();
                    text = dataSend.Rows[i]["activatecode"].ToString();
                    date = SMSservice.Database.CommonFunction.ConvertToUnixTimestamp(DateTime.Now);
                    result = sendMessage(phone, text);

                    if (result)
                    {
                        database.updateSMS(id, date);
                        result = false;
                    }
                    Thread.Sleep(1000);
                }
            }
        }
        
    }
}
